#include "chargerc.h"
#include "types.h"
#include "charger.h"
#include "vin_det.h"
#include "temp_sensor.h"
#include "adc.h"
#include "hal-regs.h"
#include "debug.h"

#define CHG_EN_TC()           CHGCON1 &= ~0x20
#define CHG_DIS_TC()          CHGCON1 |= 0x20
#define CHG_IMOD_REDUCTION()  CHGCON2 &= ~0x40
#define CHG_IMOD_NORMAL()     CHGCON2 |= 0x40


#define VSET_42  0x02
#define VSET_44  0x06
#define ISET_150 0x10
#define ISET_250 0x20
#define ISET_350 0x30
#define ISET_450 0x40

#define ISET2REG(val)    ((val) / 50 - 1)

void charger_set_vset(uint16_t mv);
void charger_set_iset(uint8_t reg_val);
void charger_set_iterm(uint8_t reg_val);
void charger_set_imod(uint8_t is_normal);
void update_force_istop_time(uint16_t vbat, uint8_t cfg, uint8_t update);
void force_isop_confirm(uint16_t vbat, uint16_t full_volt, chg_en);
bool charger_is_end(void);

bool is_charging;
uint16_t inital_vbat;
bool in_force_istop;
uint16_t force_istop_cnt;
uint16_t force_istop_time;

void chargerc_handle(void)
{
    bool enable_charger;
    uint8_t chg_config;
    static uint8_t chg_config_prev;
    uint16_t vbat;
    uint8_t can_update_time;

    vbat = adc_get_vbat();
    chg_config = temp_sensor_get_range();

    if (!temp_is_abnormal() && vin_is_ok()) {
        enable_charger = 1;
    } else {
        enable_charger = 0;
    }

    if (enable_charger) {
        if (vbat < 2200) {           /* 150mA * 0.1 */
            CHG_EN_TC();
            CHGCON3 = (CHGCON3 & 0x07) | ISET_150;
            CHG_IMOD_NORMAL();
        } else if (vbat < 2800) {    /* 350mA * 1/4 */
            CHG_IMOD_REDUCTION();
            CHGCON3 = (CHGCON3 & 0x07) | ISET_350;
            CHG_DIS_TC();
        } else {
            can_update_time = !is_charging || (chg_config != chg_config_prev);
            switch (chg_config) {
                case TEMP_RANGE_LOW_WARNING:
                    if (in_force_istop) {
                        if (charger_is_end()) {
                            CHG_IMOD_REDUCTION();
                            CHGCON3 = (ISET_350 | VSET_44);
                            in_force_istop = 0;
                        } else {
                            CHGCON3 = (ISET_450 | VSET_44);
                            CHG_IMOD_NORMAL();
                        }
                    } else {
                        CHG_IMOD_REDUCTION();
                        CHGCON3 = (ISET_350 | VSET_44);
                    }
                    update_force_istop_time(vbat, TEMP_RANGE_LOW_WARNING, can_update_time);
                    force_isop_confirm(vbat, 4360, is_charging);
                    break;
                
                case TEMP_RANGE_NORMAL:
                    CHG_IMOD_NORMAL();
                    CHGCON3 = (ISET_450 | VSET_44);
                    break;
                
                case TEMP_RANGE_HIGH_WARNING:
                    if (in_force_istop) {
                        if (charger_is_end()) {
                            CHGCON3 = (ISET_250 | VSET_42);
                            in_force_istop = 0;
                        } else {
                            CHGCON3 = (ISET_450 | VSET_42);
                        }
                    } else {
                        CHGCON3 = (ISET_250 | VSET_42);
                    }
                    CHG_IMOD_NORMAL();
                    update_force_istop_time(vbat, TEMP_RANGE_LOW_WARNING, can_update_time);
                    force_isop_confirm(vbat, 4160, is_charging);
                    break;
            }
        }

        charger_enable();
        is_charging = 1;
    } else {
        is_charging = 0;
        charger_disable();
    }

    debug_print("%x ", CHGCON0);
    debug_print("%x ", CHGCON1);
    debug_print("%x ", CHGCON2);
    debug_print("%x ", CHGCON3);
    debug_print("%x ", CHGSTAT);
    debug_print("%d ", chg_config);
    debug_print("%d ", in_force_istop);
    debug_print("%d ", force_istop_cnt);
    debug_print("%d\n", force_istop_time);

    chg_config_prev = chg_config;
}

void force_isop_confirm(uint16_t vbat, uint16_t full_volt, chg_en)
{
    if ((vbat >= full_volt) && !charger_is_end() && !in_force_istop) {
        if (++force_istop_cnt > force_istop_time) {
            force_istop_cnt = 0;
            in_force_istop = 1;
        }
    } else {
        force_istop_cnt = 0;
    }

    if (!chg_en) {
        force_istop_cnt = 0;
        in_force_istop = 0;
    }
}

bool charger_is_end(void)
{
    return CHARGER_IS_END();
}

void charger_enable(void)
{
    CHARGER_ENABLE();
}

void charger_disable(void)
{
    CHARGER_DISABLE();
    is_charging = 0;
}

bool charger_is_full(void)
{
    return 0;
}

void charger_set_vset(uint16_t mv)
{
    if (mv == 4400) {
        CHGCON3 = (CHGCON3 & 0xF8) | 0x06;
    } else {
        CHGCON3 = (CHGCON3 & 0xF8) | 0x02;
    }
}

void charger_set_iset(uint8_t reg_val)
{
    CHGCON3 = (CHGCON3 & 0x07) | (reg_val << 3);
}

void charger_set_iterm(uint8_t reg_val)
{
    CHGCON0 = (CHGCON0 & 0xFC) | reg_val;
}

void charger_set_imod(uint8_t is_normal)
{
    if (is_normal) {
        CHG_IMOD_NORMAL();
    } else {
        CHG_IMOD_REDUCTION();
    }
}

void update_force_istop_time(uint16_t vbat, uint8_t cfg, uint8_t update)
{
    if (update) {
        if (!is_charging) {
            vbat += 40;
        }

        if (cfg == TEMP_RANGE_HIGH_WARNING) {
            if (vbat >= 4200) {
                force_istop_time = 900;
            } else if (vbat >= 4180) {
                force_istop_time = 2400;
            } else {
                force_istop_time = 3900;
            }
        } else {
            force_istop_time = 7800;
        }
    }
}

#if 0
void chargerc_test_0(void)
{
    static uint16_t stp;
    static uint8_t f_cnt;
    static uint8_t dcout_cnt;
    static uint8_t on_cnt;

//    debug_print("%d ", stp);
//    debug_print("%d ", charger_is_enable);
//    debug_print("%d \n", adc_get_vbat());

    CHGCON3 = 0x22;
    CHGCON0 = (CHGCON0 & 0xFC) | 0x01;

    if (vin_is_ok()) {
        debug_print("charge end\n", 0);
    }

    if (vin_is_ok()) {
        stp++;
        f_cnt++;
        dcout_cnt = 0;
        on_cnt++;
    } else {
        if (dcout_cnt++ > 5) {
            dcout_cnt = 0;
            stp   = 0;
            f_cnt = 0;
            on_cnt = 0;
        }
    }

    if (on_cnt == 0) {
        charger_disable();
    } else if (on_cnt < 31) {
        charger_enable();
    } else {
        on_cnt = 0xFF;
    }
}
#endif
